﻿using System;
using System.Reflection;
using System.ServiceModel;
using Jsdl.Converters;
using Jsdl.Domain;
using Jsdl.Domain.Input.JsonService;
using Jsdl.Domain.Type;
using Newtonsoft.Json;

namespace Jsdl
{
    public class JsdlServiceFileGenerator 
	{
		private JsdlService _service;
        private readonly Type _serviceType;
        private readonly JsdlTypeGenerator _typeGenerator;

        public JsdlServiceFileGenerator(Type serviceType)
        {
            _typeGenerator = new JsdlTypeGenerator();
            _serviceType = serviceType;
        }

        public string Generate()
		{
			_service = new JsdlService();

            foreach (var method in _serviceType.GetMethods())
			{
				var operationAttribute = method.GetCustomAttribute<OperationContractAttribute>(true); 
				if (operationAttribute != null)
				{
					var name = operationAttribute.Name ?? method.Name; 

					var operation = new JsdlOperation();
					operation.Envelope = JsdlOperationEnvelope.json;
					operation.Transport = JsdlOperationTransport.post;
					operation.ContentTypeRaw = "application/json";
                    operation.Target = "JsdlServices/" + _serviceType.Name + "?operation=" + name;

					foreach (var param in method.GetParameters())
					{
						var paramType = param.ParameterType;

                        var parameter = _typeGenerator.GenerateType<JsdlServiceParameter>(paramType);
						parameter.Name = param.Name;

						if (paramType.IsValueType || (paramType.IsGenericType && paramType.GetGenericTypeDefinition() != typeof(Nullable<>)))
							parameter.RequiredRaw = true;
						
						operation.Parameters.Add(parameter);
					}
					
					if (method.ReturnType != typeof(void))
                        operation.Returns = _typeGenerator.GenerateType<JsdlType>(method.ReturnType);
                    _service.Operations.Add(_typeGenerator.ConvertName(name), operation);
				}
			}

            _service.Types = _typeGenerator.Types;
			return JsonConvert.SerializeObject(_service, new JsonSerializerSettings
			{
				NullValueHandling = NullValueHandling.Ignore, 
				Converters = { new EnumConverter() }
			});
		}
	}
}
